/*
 * @Author: lande 615542329@qq.com
 * @Date: 2023-02-21 14:12:12
 * @LastEditors: lande 615542329@qq.com
 * @LastEditTime: 2023-03-10 17:30:26
 * @FilePath: \GitStorage\Cloud_Control\Clound_Control.js
 * @Description: 手机控制台
 * @version: 1.0.2
 * @package: com.armclouding.goseaauto
 * @签名文件: goseaauto.jks
 * @签名文件密码: goseaauto
 * @别名: goseaautoex
 * @别名: goseaautoex
 * @g国家代码:CN
 */

importClass(android.util.Base64);

/*
 * 参考：https://github.com/lepon/websocket-heartbeat-js
 * pingTimeout  每隔多少秒发送一次心跳，如果收到任何后端消息定时器将会重置
 * pongTimeout  ping消息发送之后，10秒内没收到后端消息便会认为连接断开
 * reconnectTimeout  尝试重连的间隔时间
 * pingMsg  ping消息值
 * repeatLimit  重连尝试次数。默认不限制
 */
function WebsocketHeartbeatJs({
    url,
    pingTimeout,
    pongTimeout,
    reconnectTimeout,
    pingMsg,
    repeatLimit
}) {
    this.opts = {
        url: url,
        pingTimeout: pingTimeout,
        pongTimeout: pongTimeout,
        reconnectTimeout: reconnectTimeout,
        pingMsg: pingMsg,
        repeatLimit: repeatLimit
    };
    this.ws = null;//websocket实例
    this.repeat = 0;

    //override hook function
    this.onclose = () => { };
    this.onerror = () => { };
    this.onopen = () => { };
    this.onmessage = () => { };
    this.onreconnect = () => { };
    this.createWebSocket();
}

WebsocketHeartbeatJs.prototype.createWebSocket = function () {
    try {
        // this.ws = new WebSocket(this.opts.url);
        console.log("url: ", this.opts.url);
        this.ws = $web.newWebSocket(this.opts.url, { eventThread: 'this' });
        console.log(this.ws, "---", typeof this.ws);
        this.initEventHandle();
    } catch (e) {
        this.reconnect();
        throw e;
    }
};


/**
 * @description: 初始化时间句柄
 * @return {*}
 */
WebsocketHeartbeatJs.prototype.initEventHandle = function () {
    this.ws.on('closed', (code, reason, ws) => {
        log('closed');
        this.onclose();
        this.reconnect();
    });

    /*
    this.ws.on('closing', (code, reason, ws) => {
        log('closing')
        this.onclose();
        this.reconnect();
    });
    */

    this.ws.on('failure', (err, res, ws) => {
        log('failure');
        this.reconnect();
    });

    this.ws.on('error', (err, res, ws) => {
        log('error');
        this.onerror();
        this.reconnect();
    });

    this.ws.on('open', (res, ws) => {
        log('open');
        log('open res --> ' + res);
        this.repeat = 0;
        this.onopen();
        //心跳检测重置
        this.heartCheck();
    });

    this.ws.on('text', (event, ws) => {
        this.onmessage(event, ws);
        //如果获取到消息，心跳检测重置
        //拿到任何消息都说明当前连接是正常的
        this.heartCheck();
    });

    //二进制的消息（自己完善吧）
    /*
    this.ws.on("binary", (bytes, ws) => {
        console.info("收到二进制消息:");
        console.info("hex: ", bytes.hex());
        console.info("base64: ", bytes.base64());
        console.info("md5: ", bytes.md5());
        console.info("size: ", bytes.size());
        console.info("bytes: ", bytes.toByteArray());
    });
    */
};

WebsocketHeartbeatJs.prototype.reconnect = function () {
    if (this.opts.repeatLimit > 0 && this.opts.repeatLimit <= this.repeat) return;//limit repeat the number
    if (this.lockReconnect || this.forbidReconnect) return;
    this.lockReconnect = true;
    this.repeat++;//必须在lockReconnect之后，避免进行无效计数
    this.onreconnect();
    //没连接上会一直重连，设置延迟避免请求过多
    setTimeout(() => {
        this.createWebSocket();
        this.lockReconnect = false;
    }, this.opts.reconnectTimeout);
};

WebsocketHeartbeatJs.prototype.send = function (msg) {
    this.ws.send(JSON.stringify(msg));
};

//心跳检测
WebsocketHeartbeatJs.prototype.heartCheck = function () {
    this.heartReset();
    this.heartStart();
};

WebsocketHeartbeatJs.prototype.heartStart = function () {
    if (this.forbidReconnect) return;//不再重连就不再执行心跳

    this.pingTimeoutId = setTimeout(() => {
        //这里发送一个心跳，后端收到后，返回一个心跳消息，
        //onmessage拿到返回的心跳就说明连接正常
        this.ws.send(JSON.stringify(this.opts.pingMsg));
        //如果超过一定时间还没重置，说明后端主动断开了
        this.pongTimeoutId = setTimeout(() => {
            //如果onclose会执行reconnect，我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
            this.ws.close(1000, null);//1000表示正常关闭
        }, this.opts.pongTimeout);
    }, this.opts.pingTimeout);
};

WebsocketHeartbeatJs.prototype.heartReset = function () {
    if (this.pingTimeoutId) {
        clearTimeout(this.pingTimeoutId);
    }

    if (this.pongTimeoutId) {
        clearTimeout(this.pongTimeoutId);
    }
};

WebsocketHeartbeatJs.prototype.close = function () {
    //如果手动关闭连接，不再重连
    this.forbidReconnect = true;
    this.heartReset();
    this.ws.close(1000, null);//1000表示正常关闭
};

/**
 * @description: 获取资源ID
 * @return {String} String 成功返回资源ID ，失败返回null
 */
function getResourceId() {
    try {
        let res = http.get("http://localhost:9898/gosea/deviceResourceId");
        let retJson = res.body.json();
        if (retJson.code == 200) {
            return retJson.data.deviceResourceId;

        }
    } catch (error) {
        alert('获取资源ID报错: ', error);
    }
    return null;
}

const resourceId = getResourceId();
console.log("resourceId:", resourceId);
if (!resourceId) {
    alert("失败-获取资源id");
}

const options = {
    // url: 'ws://101.43.125.159/',//ip地址，请修改为websocket服务端对应地址
    // url: 'ws://14.18.190.138:48888/ws?sn=01',
    // url: 'ws://192.168.80.33:10000/ws?resourceId=' + 91689,
    // url: 'ws://lh123.ittun.com/ws?resourceId=11',
    url: 'ws://14.18.190.140:8029//ws?resourceId=' + resourceId,
    pingTimeout: 30 * 1000,
    pongTimeout: 90 * 1000,
    reconnectTimeout: 3000,
    pingMsg: { "type": "ping" },
    repeatLimit: 10
}

let enginesId = null;
let storage = storages.create("biyun");
// 初始化设备状态 false为空闲状态，true为任务中
// storage.put("deviceStatus", false);

let ControlObj = new Control();
let websocketHeartbeatJs = new WebsocketHeartbeatJs(options);
console.log("websocketHeartbeatJs: ", websocketHeartbeatJs);
websocketHeartbeatJs.onopen = function () {
    console.log('connect success');
    websocketHeartbeatJs.send({ "type": "ping" });
    log('send hello');
}

websocketHeartbeatJs.onmessage = function (msg, ws) {
    // console.log('onmessage: ' + msg);
    if (msg == 'close') {
        websocketHeartbeatJs.close();
        return;
    }

    ControlObj.main(msg);
}

websocketHeartbeatJs.onreconnect = function () {
    log('reconnecting...');
}

websocketHeartbeatJs.onclose = function () {
    log('close...');
}

setInterval(() => { }, 10000);

function Control() {
    this.msg = null;
    this.pathCode = null;
    this.pathCodeDir = "/sdcard/code/";
    this.enginesId = null;
    this.downloadCodeUrl = "http://110.53.221.195:8210/document/newFile/download/1/d64db0da6c8b4ea086eb/"
    // this.detailId = null;
    this.main = function (msg) {
        try {
            this.msg = JSON.parse(msg);
            // console.log("websocket_onmessage: ", this.msg);
            // let detailId = "none";
            // 添加一个关闭任务的设置

            // 设备不空闲，直接返回。
            // if (storage.get("deviceStatus", false)) {
            //     console.log("设备正在任务中...");
            //     return;
            // }
            console.log("this.msg.type: ", this.msg.type);
            // console.log("this.msg.data.detailId: ", this.msg.data.detailId);
            // console.log("this.detailId: ", this.detailId);
            // try {
            //     detailId = this.msg.data.detailId ?
            //         this.msg.data.detailId
            //         : "none";
            // } catch (error) {
            //     detailId = "none";
            // }

            if (this.msg.type === "pong") {
                return;
            } else if (this.msg.type === "change_proxy") {
                storage.put("vpnlink", this.msg.data);
                console.log("成功-获取vpn订阅链接");
                return;
            }

            // else if (this.detailId === detailId) {
            //     console.log("任务相同，不重复执行");
            //     return;
            // }
            // this.detailId = detailId;

            /* 
                {
                "id": "消息id，一个10位的随机数",
                "type": "消息的指令类型，标识着唯一的一种指令" ,
                "data":"自定义数据，可以是任意数据格式，每个指令自己定义"
                }
            */

            storage.put("wsMsg", this.msg);
            console.log("ws推送的信息: ", storage.get("wsMsg"));
            this.getCodeFile();
            this.enginesLoad(this.pathCode);

        } catch (error) {
            console.log("控制台main报错: ", error);
        }
    }



    this.getCodeFile = function () {
        try {
            this.downloadCodeFile("LowLevelMultipartUpload_28306508649888153688", "diy_module.js");
            console.log("完成-下载模块文件 ");
            console.log("this.msg.type: ", this.msg.type);
            switch (this.msg.type) {
                case '"task_register_wa"':
                    console.log("执行任务-ws注册");
                    this.downloadCodeFile("LowLevelMultipartUpload_28097505542882918488", "whatsapp_register.js");

                    break;
                case "publish_wa":
                    this.downloadCodeFile("LowLevelMultipartUpload_28480461901543014466", "whatsapp_sendmsg.js");
                    break;
                default:
                    break;
            }

        } catch (error) {
            console.log("返回代码文件报错1: ", error);
        }
    }

    /**
     * @description: 下载脚本文件
     * @param {*} keyFile 上传文件，返回的keyFile码
     * @param {*} codeName 代码名字
     * @return {*}
     */
    this.downloadCodeFile = function (keyFile, codeName) {
        this.pathCode = this.pathCodeDir + codeName;
        files.ensureDir(this.pathCodeDir);
        files.remove(this.pathCode);
        try {
            let url = this.downloadCodeUrl + keyFile;
            console.log("下载代码文件URL: ", url);
            res = http.get(url);
            if (res.statusCode == 200) {
                let fileBytes = res.body.bytes();
                files.writeBytes(this.pathCode, fileBytes);
                sleep(1000);
                console.log("下载文件完成");
            }

        } catch (error) {
            console.log("下载文件报错：", error);
        }
    }

    /**
     * @description: 加载引擎
     * @param {*} pathCode 代码路径
     * @return {*}
     */
    this.enginesLoad = function (pathCode) {
        try {
            console.log("引擎正在加载。。。");
            this.enginesId = engines.execScriptFile(pathCode, {
                path: this.pathCodeDir
            });
            console.log("引擎ID: ", this.enginesId);
            enginesId = this.enginesId;
        } catch (error) {
            console.log("引擎启动报错: ", error);
        }
    }
}